package com.bskj.common.utils;

import java.beans.PropertyDescriptor;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;

import com.alibaba.fastjson.JSONObject;

/**
 * Created by shiyuan on 2018/5/2.
 */
public class DigestUtil {
	private static Logger logger = LoggerFactory.getLogger(DigestUtil.class);
	private static Map<String, PropertyDescriptor[]> descriptors = new HashMap<String, PropertyDescriptor[]>();

	public static String digestKeyValue(String key, Object object) {
		String src = generateMab(object, true, true);
		src = src + "&key=" + key;
		logger.info("md5源字符串:" + src);
		String digest = md5WithUtf8(src).toUpperCase();
		logger.info("md5值:" + digest);
		return digest;
	}

	public static String digestKeyValue(String key, String content) {
		String src = content + "&key=" + key;
		logger.info("md5源字符串:" + src);
		String digest = md5WithUtf8(src).toUpperCase();
		logger.info("md5值:" + digest);
		return digest;
	}

	public static String digestValue(String key, Object object) {
		String src = generateMab(object, false, true);
		src = src + key;
		logger.info("md5源字符串:" + src);
		String digest = md5WithUtf8(src).toUpperCase();
		logger.info("md5值:" + digest);
		return digest;
	}

	public static String digestValueCompatible(String key, Object object, boolean withSplitChar) {
		String src = generateMab(object, false, withSplitChar);
		src = src + key;
		logger.info("md5源字符串:" + src);
		String digest = md5WithUtf8(src).toUpperCase();
		logger.info("md5值:" + digest);
		return digest;
	}
	
	public static String sha256_HMAC(String message, String secret) {
		String hash = "";
		try {
			message += "&key="+secret;
			Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
			SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
			sha256_HMAC.init(secret_key);
			byte[] bytes = sha256_HMAC.doFinal(message.getBytes());
			hash = parseByte2HexStr(bytes);
		} catch (Exception e) {
			System.out.println("Error HmacSHA256 ===========" + e.getMessage());
		}
		return hash;
	}
	
	public static String parseByte2HexStr(byte buf[]) {
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < buf.length; i++) {
			String hex = Integer.toHexString(buf[i] & 0xFF);
			if (hex.length() == 1) {
				hex = '0' + hex;
			}
			sb.append(hex.toUpperCase());
		}
		return sb.toString();
	}

	private static String generateMab(Object e, boolean keyValueFormat, boolean usingSplitChar) {
		PropertyDescriptor[] properties = descriptors.get(e.getClass().getName());
		if (null == properties) {
			synchronized (descriptors) {
				properties = descriptors.get(e.getClass().getName());
				if (null == properties) {
					properties = BeanUtils.getPropertyDescriptors(e.getClass());
					descriptors.put(e.getClass().getName(), properties);
				}
			}
		}

		SortedMap<String, String> items = new TreeMap<String, String>();
		for (int i = 0; i < properties.length; i++) {
			PropertyDescriptor p = properties[i];
			if ("class".equals(p.getName())) {
				continue;
			}
			try {
				Object result = p.getReadMethod().invoke(e);
				if (null != result) {
					if (result instanceof String) {
						items.put(p.getName(), (String) result);
					} else {
						String temp = result.toString();
						items.put(p.getName(), temp);
					}
				}
			} catch (Exception ex) {
				logger.error(ex.getMessage());
			}
		}
		StringBuilder builder = new StringBuilder();
		Iterator<String> itMap = items.keySet().iterator();
		while (itMap.hasNext()) {
			String key = itMap.next();
			String value = items.get(key);
			if (!StringUtils.isEmpty(value) && !"class".equals(key) && !"digest".equals(key) && !"sign".equals(key)) {
				logger.info("Key:" + key + ", value:" + value);
				if (keyValueFormat) {
					builder.append(key).append("=").append(value);
				} else {
					builder.append(value);
				}
				if (usingSplitChar && itMap.hasNext()) {
					builder.append("&");
				}
			}
		}
		String src = builder.toString();
		if (src.endsWith("&")) {
			return src.substring(0, src.length() - 1);
		} else {
			return src;
		}
	}

	public static String md5WithUtf8(String s) {
		char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
		try {
			byte[] btInput = s.getBytes("utf-8");
			// 获得MD5摘要算法的 MessageDigest 对象
			MessageDigest mdInst = MessageDigest.getInstance("MD5");
			// 使用指定的字节更新摘要
			mdInst.update(btInput);
			// 获得密文
			byte[] md = mdInst.digest();
			// 把密文转换成十六进制的字符串形式
			int j = md.length;
			char str[] = new char[j * 2];
			int k = 0;
			for (int i = 0; i < j; i++) {
				byte byte0 = md[i];
				str[k++] = hexDigits[(byte0 >>> 4) & 0xf];
				str[k++] = hexDigits[byte0 & 0xf];
			}
			return new String(str);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
	
	
	
	public static void main(String[] args) {
		JSONObject signObj = new JSONObject();
		signObj.put("abc", "123");
		signObj.put("bcd3", "211");
		
		String src = "";
		List<String> keyList = new ArrayList<>();
		for (String key : signObj.keySet()) {
			keyList.add(key);
		}
		Collections.sort(keyList);
		for (String key : keyList) {
			src += (key + "=" + signObj.get(key) + "&");
		}
		src = src.substring(0, src.length() - 1);
		String afterSignStr = DigestUtil.sha256_HMAC(src,"123456");
		System.out.println(afterSignStr);
	}
}
